#pragma once
#include <string>
#include <jsoncpp/json/json.h>
#include "Socket.hpp"
#include <cstring>
#include <memory>
#include <functional>

// 将消息进行序列化和反序列化处理

// 客户端->服务器   需要计算的信息
class Request
{
public:
    Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper)
    {
    }
    ~Request() {}
    Request() {}

    // 序列化
    std::string Serialize()
    {
        // _x = 10 _y = 20, _oper = '+'
        // "10" "20" '+' : 用空格作为分隔符
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;
        Json::FastWriter Writer;
        return Writer.write(root);
    }
    // 反序列化
    bool Deserialize(std::string &in)
    {
        // "10" "20" '+' -> 以空格作为分隔符 -> 10 20 '+'
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ok;
    }
    int X() { return _x; }
    int Y() { return _y; }
    char Oper() { return _oper; }

private:
    int _x;
    int _y;
    char _oper;
};

// 服务器->客户端   计算的结果
class Response
{
public:
    Response(int result, int code) : _result(result), _code(code)
    {
    }
    ~Response() {}
    Response() {}

    // 序列化
    std::string Serialize()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;
        Json::FastWriter Writer;
        return Writer.write(root);
    }
    // 反序列化
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return ok;
    }
    void SetResult(int result) { _result = result; }
    void SetCode(int code) { _code = code; }
    int GetResult(){return _result;}
    int GetCode(){return _code;}
private:
    int _result;
    int _code;
};

// 客户端将信息序列化之后发送到缓冲区，因为tcp传输是面向字节流的，我们不知道客户端向缓冲区
// 发送了多少数据，当然服务器也不知道在接收缓冲区里读了多少数据，这个时候就需要对序列化的数据进行处理

const std::string sep = "\r\n";
using func_t = std::function<Response(Request &req)>;
class Protocal
{
public:
    Protocal() {}
    Protocal(func_t fun) : _fun(fun) {}
    ~Protocal() {}
    // 对需要发送的报文进行封装
    std::string Encode(const std::string &jsonstr)
    {
        return std::to_string(jsonstr.size()) + sep + jsonstr + sep;
    }

    // 对有效报文进行提取，如果报文不完整，或者读到的报文信息过量，则将一条有效的报文提取出来
    bool Decode(std::string &buffer, std::string *package) // package是输出型参数，将有效报文提取
    {
        size_t pos = buffer.find(sep);
        if (pos == std::string::npos)
            return false; // 没有找到第一个分隔符，返回继续读

        std::string num_str = buffer.substr(0, pos);
        int pack_len = std::stoi(num_str);
        // 读到了第一个分隔符
        // 如果读到的报文大于等于有效报文，就可以对数据进行提取，并将该条报文从缓冲区删除
        if (buffer.size() < pack_len)
        {
            return false;
        }
        // 1.将buff上的一条报文截取
        int josn_len = sep.size() * 2 + pack_len + num_str.size();
        *package = buffer.substr(pos + sep.size(), pack_len);
        buffer.erase(0, josn_len);
        return true;
    }

    void GetRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        std::string buff_queue;
        while (true)
        {
            int n = sock->Recv(&buff_queue);
            if (n > 0)
            {
                // 1.对客户端发送过来的报文进行解包，提取有效报文
                std::string josn_str;
                while (Decode(buff_queue, &josn_str))
                {
                    // 2.拿到了一条有效报文,进行反序列化
                    Request rq;
                    bool ok = rq.Deserialize(josn_str);
                    if (!ok)
                    {
                        // 反序列化失败
                        continue;
                    }
                    // 成功拿到数据
                    // 3.对数据进行处理,拿到结果
                    Response rp = _fun(rq);
                    // 4.对处理完的数据进行序列化发送给客户端
                    std::string result_str = rp.Serialize();
                    // 5.进行封装
                    std::string result_josn = Encode(result_str);
                    // 6.发送
                    sock->Send(result_josn);
                }
            }
            else if (n == 0)
            {
                std::cout << "客户端" << client.GetName() << "退出了" << std::endl;
                break;
            }
            else
            {
                std::cout << "Recv 异常" << std::endl;
                break;
            }
        }
    }

    bool GetResponse(std::shared_ptr<Socket> &client, std::string buff_str, Response *rep)
    {
        // 从缓冲区读取报文->解析报文->反序列化->将带有Response返回
        while (true)
        {
            int n = client->Recv(&buff_str);
            if (n > 0)
            {
                std::string rep_str;
                while(Decode(buff_str,&rep_str))
                {
                    //提取一条有效报文
                    //进行反序列化
                    rep->Deserialize(rep_str);
                }
                return true;
            }
            else if (n == 0)
            {
                std::cout << "server quit " << std::endl;
                return false;
            }
            else
            {
                std::cout << "recv error" << std::endl;
                return false;
            }
        }
    }
    std::string BuidSendStr(int x, int y, char oper)
    {
        Request req(x, y, oper);
        std::string req_str = req.Serialize();
        return Encode(req_str);
    }

private:
    func_t _fun;
};